package src.E_Thread;
// 生产者消费者模型

import java.util.concurrent.CountDownLatch;

// 实现二（信号灯法，采用 阻塞队列 方式）
public class E17_SignalLamp {
    public static void main(String[] args) throws InterruptedException {
        // 相当于门栓，当所有线程跑到标记位才会开门，先到的就等，2为线程数，每遇到一个门栓-1
        CountDownLatch countDownLatch = new CountDownLatch(2);
        Pen pen = new Pen();
        PenConsumer pc = new PenConsumer(pen, countDownLatch);
        PenProducer pp = new PenProducer(pen, countDownLatch);
        new Thread(pc).start();
        new Thread(pp).start();
        // 0.001秒后全局停止生产和消耗
        Thread.sleep(1);
        pen.setFlag(false);
        countDownLatch.await(); // 设置主线程在此等待上面两个线程执行完，直到上面的2减到0，再接着执行下面的代码
    }
}

// 产品（笔）
class Pen{
    private int penId; // 笔编号
    private boolean penFlag = false; // 单笔生产信号灯
    private boolean flag = true; // 全局信号灯

    public int getPenId() {
        return penId;
    }

    public void setPenId(int penId) {
        this.penId = penId;
    }

    public boolean isPenFlag() {
        return penFlag;
    }

    public void setPenFlag(boolean penFlag) {
        this.penFlag = penFlag;
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}

// 生产者
class PenProducer implements Runnable{

    CountDownLatch countDownLatch;

    @Override
    public void run() {
        production();
    }

    // 生产
    private final Pen pen;

    public PenProducer(Pen pen, CountDownLatch countDownLatch) {
        this.pen = pen;
        this.countDownLatch = countDownLatch;
    }

    public void production(){
        int a = 0;
        while (this.pen.isFlag()){
            synchronized (this.pen){
                // 单笔未生产完毕，让消费者等待，默认false
                if (this.pen.isPenFlag()){
                    try {
                        this.pen.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                // 开始生产
                this.pen.setPenId(++a);
                this.pen.setPenFlag(true);
                System.out.println("生产笔"+a);
                this.pen.notify(); // notify()方法——随机唤醒一个wait的线程，这里特指了一条线程
            }
        }
        System.out.println("停止生产！");
        // 确保生产者没有死亡的情况下，消费者不能死（门栓-1）
        countDownLatch.countDown();
    }
}

// 消费者
class PenConsumer implements Runnable{

    CountDownLatch countDownLatch;

    @Override
    public void run() {
        consumption();
    }

    // 消费
    private final Pen pen;

    public PenConsumer(Pen pen, CountDownLatch countDownLatch) {
        this.pen = pen;
        this.countDownLatch = countDownLatch;
    }

    public void consumption(){
        while (this.pen.isFlag()){
            synchronized (this.pen){
                // 等待生产者生产
                if (!this.pen.isPenFlag()){
                    try {
                        this.pen.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                // 开始消费
                System.out.println("消耗笔"+this.pen.getPenId());
                this.pen.setPenFlag(false); // 用完修改单笔生产状态
                this.pen.notify();
            }
        }
        // 确保生产者没有死亡的情况下，消费者不能死（门栓-1）
        countDownLatch.countDown();
        // 确保停止生产后，能够使用最后生产的一支笔
        if (this.pen.isPenFlag()) {
            System.out.println("消耗笔"+this.pen.getPenId());
        }
        System.out.println("停止消耗！");
    }
}